package wiki.xsx.core.jmeter.core.util;

import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * optional扩展
 *
 * @author xsx
 * @date 2022/8/30
 * @since 1.8
 * <p>
 * Copyright (c) 2022 xsx All Rights Reserved.
 * easy-jmeter is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
public class JmeterOptional<T> {

    /**
     * 空对象
     */
    private static final JmeterOptional<?> EMPTY = new JmeterOptional<>();

    /**
     * 值
     */
    private final T value;

    /**
     * 无参构造
     */
    private JmeterOptional() {
        this.value = null;
    }

    /**
     * 有参构造
     *
     * @param value 值
     */
    private JmeterOptional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 获取空对象
     *
     * @return 返回空对象
     */
    public static <T> JmeterOptional<T> empty() {
        @SuppressWarnings("unchecked")
        JmeterOptional<T> t = (JmeterOptional<T>) EMPTY;
        return t;
    }

    /**
     * 获取非空对象
     *
     * @param value 值
     * @return 返回非空对象
     */
    public static <T> JmeterOptional<T> of(T value) {
        return new JmeterOptional<>(value);
    }

    /**
     * 获取可空对象
     *
     * @param value 值
     * @return 返回可空对象
     */
    public static <T> JmeterOptional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * 获取值
     *
     * @return 返回值
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * 是否非空
     *
     * @return 返回布尔值，是为true，否为false
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
     * 如果非空
     *
     * @param consumer 消费者
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null) {
            consumer.accept(value);
        }
    }

    /**
     * 如果为真（值为布尔值）
     *
     * @param consumer 消费者
     */
    public void ifTrue(Consumer<? super T> consumer) {
        if (value != null && value instanceof Boolean && Boolean.parseBoolean(value.toString())) {
            consumer.accept(value);
        }
    }

    /**
     * 如果为假（值为布尔值）
     *
     * @param consumer 消费者
     */
    public void ifFalse(Consumer<? super T> consumer) {
        if (value != null && value instanceof Boolean && !Boolean.parseBoolean(value.toString())) {
            consumer.accept(value);
        }
    }

    /**
     * 过滤
     *
     * @param predicate 条件
     * @return 返回包装对象
     */
    public JmeterOptional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent()) {
            return this;
        } else {
            return predicate.test(value) ? this : empty();
        }
    }

    /**
     * 处理
     *
     * @param <U>    处理后的值类型
     * @param mapper 处理方法
     * @return 返回处理后的包装对象（可空对象）
     */
    public <U> JmeterOptional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent()) {
            return empty();
        } else {
            return JmeterOptional.ofNullable(mapper.apply(value));
        }
    }

    /**
     * 扁平化处理
     *
     * @param <U>    处理后的值类型
     * @param mapper 处理方法
     * @return 返回处理后的包装对象（非空对象）
     */
    public <U> JmeterOptional<U> flatMap(Function<? super T, JmeterOptional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent()) {
            return empty();
        } else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }

    /**
     * 或者
     *
     * @param other 默认值
     * @return 返回值（如果值非空，则返回值，否则返回默认值）
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * 或者
     *
     * @param other 默认对象
     * @return 返回对象（如果值非空，则返回当前对象，否则返回默认对象）
     */
    public JmeterOptional<T> orElse(JmeterOptional<T> other) {
        return value != null ? this : other;
    }

    /**
     * 或者
     *
     * @param other 默认值方法
     * @return 返回值（如果值非空，则返回值，否则返回默认值方法提供的值）
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

    /**
     * 或者
     *
     * @param exceptionSupplier 异常信息
     * @return 返回值（如果值非空，则返回值，否则提示异常信息）
     * @throws X 异常信息
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

    /**
     * 等于
     *
     * @param obj 比较对象
     * @return 返回布尔值，是为true，否为false
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof JmeterOptional)) {
            return false;
        }

        JmeterOptional<?> other = (JmeterOptional<?>) obj;
        return Objects.equals(value, other.value);
    }

    /**
     * 哈希码
     *
     * @return 返回哈希码
     */
    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }

    /**
     * 转字符串
     *
     * @return 返回字符串
     */
    @Override
    public String toString() {
        return value != null
                ? String.format("JmeterOptional[%s]", value)
                : "JmeterOptional.empty";
    }
}
